/*
 * ******************************************************************************
 *   Copyright (c)
 *   https://gist.github.com/chrisbanes/9091754
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 *  *****************************************************************************
 */

package it.gmariotti.cardslib.library.view;


import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.components.DirectionalLayout;
import ohos.agp.components.element.Element;
import ohos.agp.render.Canvas;
import ohos.agp.utils.Rect;
import ohos.app.Context;

import static ohos.agp.utils.LayoutAlignment.*;


public class ForegroundLinearLayout extends DirectionalLayout implements Component.DrawTask, Component.LayoutRefreshedListener {
    public static final int FILL_VERTICAL = TOP | BOTTOM;
    public static final int FILL_HORIZONTAL = LEFT | RIGHT;
    public static final int FILL = FILL_VERTICAL | FILL_HORIZONTAL;
    public static final int RELATIVE_HORIZONTAL_GRAVITY_MASK = START | END;
    /**
     * Raw bit indicating the gravity for an axis has been specified.
     */
    public static final int AXIS_SPECIFIED = 0x0001;

    /**
     * Raw bit controlling how the left/top edge is placed.
     */
    public static final int AXIS_PULL_BEFORE = 0x0002;
    /**
     * Raw bit controlling how the right/bottom edge is placed.
     */
    public static final int AXIS_PULL_AFTER = 0x0004;
    /**
     * Bits defining the vertical axis.
     */
    public static final int AXIS_Y_SHIFT = 4;
    public static final int VERTICAL_GRAVITY_MASK = (AXIS_SPECIFIED |
            AXIS_PULL_BEFORE | AXIS_PULL_AFTER) << AXIS_Y_SHIFT;
    private Element mForeground;

    private final Rect mSelfBounds = new Rect();
    private final Rect mOverlayBounds = new Rect();

    private int mForegroundGravity = FILL;

    protected boolean mForegroundInPadding = true;

    boolean mForegroundBoundsChanged = false;

    public ForegroundLinearLayout(Context context) {
        super(context);
    }

    public ForegroundLinearLayout(Context context, AttrSet attrs) {
        this(context, attrs, "0");
    }

    public ForegroundLinearLayout(Context context, AttrSet attrs, String defStyle) {
        super(context, attrs, defStyle);
        mForegroundGravity = attrs.getAttr("foregroundGravity").isPresent() ? attrs.getAttr("foregroundGravity").get().getIntegerValue() : mForegroundGravity;
        final Element d = attrs.getAttr("foreground").get().getElement();
        if (d != null) {
            setForeground(d);
        }
        setLayoutRefreshedListener(this);
        addDrawTask(this);
    }

    /**
     * Describes how the foreground is positioned.
     *
     * @return foreground gravity.
     * @see #setForegroundGravity(int)
     */
    public int getForegroundGravity() {
        return mForegroundGravity;
    }

    /**
     * Describes how the foreground is positioned. Defaults to START and TOP.
     *
     * @param foregroundGravity See {@link }
     * @see #getForegroundGravity()
     */
    public void setForegroundGravity(int foregroundGravity) {
        if (mForegroundGravity != foregroundGravity) {
            if ((foregroundGravity & RELATIVE_HORIZONTAL_GRAVITY_MASK) == 0) {
                foregroundGravity |= START;
            }

            if ((foregroundGravity & VERTICAL_GRAVITY_MASK) == 0) {
                foregroundGravity |= TOP;
            }

            mForegroundGravity = foregroundGravity;

            if (mForegroundGravity == FILL && mForeground != null) {
                Rect padding = new Rect();
                //todo 这段代码好像没啥意义
                //mForeground.getPadding(padding);
            }

            postLayout();
        }
    }

    //todo openHarmony does not have this method.
//    @Override
//    protected boolean verifyDrawable(Drawable who) {
//        return super.verifyDrawable(who) || (who == mForeground);
//    }


    //todo openHarmony does not have this method.
//    @Override
//    public void jumpDrawablesToCurrentState() {
//        super.jumpDrawablesToCurrentState();
//        if (mForeground != null) mForeground.jumpToCurrentState();
//    }

    //todo openHarmony does not have this method.
//    @Override
//    protected void drawableStateChanged() {
//        super.drawableStateChanged();
//        if (mForeground != null && mForeground.isStateful()) {
//            mForeground.setState(getDrawableState());
//        }
//    }

    /**
     * Supply a Drawable that is to be rendered on top of all of the child
     * views in the frame layout.  Any padding in the Drawable will be taken
     * into account by ensuring that the children are inset to be placed
     * inside of the padding area.
     *
     * @param drawable The Drawable to be drawn on top of the children.
     */
    public void setForeground(Element drawable) {
        if (mForeground != drawable) {

            mForeground = drawable;

            if (drawable != null) {
                //todo mo such method
//                setWillNotDraw(false);
//                drawable.setCallback(this);
                if (mForegroundGravity == FILL) {
                    Rect padding = new Rect();
                    //drawable.getPadding(padding);
                }
            }
            postLayout();
            invalidate();
        }
    }

    /**
     * Returns the drawable used as the foreground of this FrameLayout. The
     * foreground drawable, if non-null, is always drawn on top of the children.
     *
     * @return A Drawable or null if no foreground was set.
     */
    public Element getForeground() {
        return mForeground;
    }


    //todo openHarmony does not have this method.
//    @Override
//    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
//        super.onLayout(changed, left, top, right, bottom);
//        mForegroundBoundsChanged = changed;
//    }

    //todo openHarmony does not have this method.
//    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
////    @Override
////    public void drawableHotspotChanged(float x, float y) {
////        super.drawableHotspotChanged(x, y);
////        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
////            if (mForeground != null) {
////                mForeground.setHotspot(x, y);
////            }
////        }
////    }

    @Override
    public void onDraw(Component component, Canvas canvas) {
        if (mForeground != null) {
            final Element foreground = mForeground;

            if (mForegroundBoundsChanged) {
                mForegroundBoundsChanged = false;
                final Rect selfBounds = mSelfBounds;
                final Rect overlayBounds = mOverlayBounds;

                final int w = getRight() - getLeft();
                final int h = getBottom() - getTop();

//                if (mForegroundInPadding) {
//                    selfBounds.set(0, 0, w, h);
//                } else {
//                    selfBounds.set(getPaddingLeft(), getPaddingTop(),
//                            w - getPaddingRight(), h - getPaddingBottom());
//                }
                //todo no such method
//                Gravity.apply(mForegroundGravity, foreground.getIntrinsicWidth(),
//                        foreground.getIntrinsicHeight(), selfBounds, overlayBounds);
                foreground.setBounds(overlayBounds);
            }

            foreground.drawToCanvas(canvas);
        }
    }

    @Override
    public void onRefreshed(Component component) {
        mForegroundBoundsChanged = true;
    }
}